package com.gvsoft;


import com.gvsoft.Client;
import com.gvsoft.analyse.inf.IClientOrder;
import com.gvsoft.analyse.order.ClientOrder;
import com.gvsoft.log.Logs;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: zhaoqiubo
 * Date: 15/7/27
 * Time: 下午3:55
 * To change this template use File | Settings | File Templates.
 */
public class GVClientMThread extends Thread {

    protected static SocketChannel socketChannel = null;
    private final static int BLOCK = 4096;
    protected static Selector selector = null;
    private static final int PACKET_HEAD_LENGTH = 4;

    public void run() {
        Logs.info("【GVClientMThread】","服务端报文读取主线程启动……");

            while (true) {
                try {

                    selector.select(3000);

                    Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
                    for (int i = 0; keys.hasNext(); i++) {

                        SelectionKey key = keys.next();
                        keys.remove();
                        if (key.isConnectable()) {
                            socketChannel = (SocketChannel) key.channel();
                            if (socketChannel.isConnectionPending()) {
                                if (socketChannel.finishConnect()){
                                    Client.IS_CONNECT =true;
                                    Logs.info("【GVClientMThread】","-------成功连接服务端！-------");
                                }

                            }
                            socketChannel.register(selector, SelectionKey.OP_READ);
                        } else if (key.isReadable()) {
                            //获取事件key中的channel
                            socketChannel = (SocketChannel) key.channel();
                            ByteBuffer byteBuffer = ByteBuffer.allocate(BLOCK);
                            //清理缓冲区，便于使用
                            byteBuffer.clear();
                            //将channel中的字节流读入缓冲区
                            String readStr = "";
                            int count = socketChannel.read(byteBuffer);
                            //务必要把buffer的position重置为0
                            byteBuffer.flip();

                            handleRead(byteBuffer, count);
//                            socketChannel.register(selector, SelectionKey.OP_READ);
                        } else if (key.isWritable()) {
                            socketChannel.register(selector, SelectionKey.OP_READ);
                        }

                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    continue;
                }

            }

    }

    private void handleRead(ByteBuffer byteBuffer, int count) throws IOException {
        if (count > 0) {
            //标记读取缓冲区起始位置
            int location = 0;
            //如果缓冲区从0到limit的数量大于包体大小标记数字
            while (byteBuffer.remaining() > PACKET_HEAD_LENGTH) {

                String strBsize;//包体大小标记
                strBsize = new String(byteBuffer.array(), location, PACKET_HEAD_LENGTH);
                byteBuffer.position(location + PACKET_HEAD_LENGTH);//移动缓冲区position
//                Logs.info("收到服务端包体大小：" + strBsize + "，查看position变化：" + byteBuffer.position());

                int byteBufferSize = Integer.parseInt(strBsize.trim());//得到包体大小

                if (byteBuffer.remaining() >= byteBufferSize) {//如果从缓冲区当前位置到limit大于包体大小，进行包体处理

                    String strPacket = new String(byteBuffer.array(), PACKET_HEAD_LENGTH + location, byteBufferSize);
                    byteBuffer.position(location + PACKET_HEAD_LENGTH + byteBufferSize);//将缓冲区的位置移动到下一个包体大小标记位置
//                    Logs.info("收到服务端包体内容：" + strPacket + "，查看position变化：" + byteBuffer.position());

                    if (Client.MSGQUEUE.offer(strPacket.trim())) {
                        Logs.info("【GVClientMThread】","将添加至消息队列，队列内消息数量为：" + Client.MSGQUEUE.size());
                    } else {
                        Logs.info("【GVClientMThread】","消息队列已满，请增加队列容量！");
                    }
                    location = location + PACKET_HEAD_LENGTH + byteBufferSize;//设定读取缓冲区起始位置
                }
            }
            //我也不知道这是否有用，
            byteBuffer.clear();
        } else if (count == 0) {
            return;
        } else {
            socketChannel.close();
            Client.clearToken4Disconnect();
//            this.interrupt();
        }
    }


    /**
     * 向通道写入信息的方法
     *
     * @param clientOrder   报文处理类接口
     * @param socketChannel
     */
    protected static void write2Channel(IClientOrder clientOrder, SocketChannel socketChannel) throws IOException{
        try {
            socketChannel.register(selector, SelectionKey.OP_WRITE);
            //创建一个byteBuffer用来存储要写入的buffer
            ByteBuffer byteBuffer = ByteBuffer.allocate(BLOCK);
            //得出整个包体的长度
            String packetSize = Integer.toString(clientOrder.generateOrderStr().getBytes().length);
            //讲包体长度放入buffer的前四位
            byteBuffer.put(packetSize.getBytes());
            //移动buffer的postion指针到第四位，包体将从第四位开始写入
            byteBuffer.position(PACKET_HEAD_LENGTH);
            String str = clientOrder.generateOrderStr();
            //写入包体
            Logs.info("【GVClientMThread】","客户端写入通道的包体：" + str);
            byteBuffer.put(str.getBytes());
            byteBuffer.flip();
            socketChannel.write(byteBuffer);
        } catch (IOException e) {
            throw e;
        }
    }


}
